package cn.tannn.ops.util;

import cn.tannn.jdevelops.exception.built.BusinessException;
import cn.tannn.ops.nginx.controller.vo.DnsDomain;
import cn.tannn.ops.nginx.entity.CloudAccessKey;
import com.alibaba.fastjson2.JSON;
import com.huaweicloud.sdk.core.auth.BasicCredentials;
import com.huaweicloud.sdk.core.auth.ICredential;
import com.huaweicloud.sdk.core.exception.ServiceResponseException;
import com.huaweicloud.sdk.dns.v2.DnsClient;
import com.huaweicloud.sdk.dns.v2.model.*;
import com.huaweicloud.sdk.dns.v2.region.DnsRegion;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * 华为dns工具
 *
 * @author https://codelabs.developer.huaweicloud.com/codelabs/samples/19bf85e861a24b5cb8717e13179ac58a
 * @version V1.0
 * @date 2024/9/2 下午1:16
 */
public class HwDnsUtil {

    // Aliyun DNS API credentials
    // https://ram.console.aliyun.com/users/detail?userId=203193816817432348&activeTab=PermissionList
    // 记得设置权限管理 - 管理云解析（DNS）的权限，管理公共DNS（PubDNS）的权限，管理HTTPDNS的权限
    private static final Logger LOG = LoggerFactory.getLogger(HwDnsUtil.class);

    /**
     * Init 初始化客户端
     *
     * @param cloud 密钥数据
     * @return Client
     */
    @SneakyThrows
    public static DnsClient init(CloudAccessKey cloud) {
        return init(cloud.getAccessId(), cloud.getAccessSecret());
    }

    /**
     * Init 初始化客户端
     * <p>
     * 启动的时候添加环境变量  HUAWEI_CLOUD_ACCESS_KEY_ID 和 HUAWEI_CLOUD_ACCESS_KEY_SECRET
     * </p>
     *
     * @return Client
     */
    @SneakyThrows
    public static DnsClient init() {
        String accessKeyId = System.getenv("HUAWEI_CLOUD_ACCESS_KEY_ID");
        String accessKeySecret = System.getenv("HUAWEI_CLOUD_ACCESS_KEY_SECRET");
        return init(accessKeyId, accessKeySecret);
    }

    /**
     * Init 初始化客户端
     *
     * @param accessKeyId     密钥Id
     * @param accessKeySecret 密钥
     * @return Client
     */
    @SneakyThrows
    public static DnsClient init(String accessKeyId, String accessKeySecret) {
        String endpoint = "https://vpc.cn-north-4.myhuaweicloud.com";
        ICredential auth = new BasicCredentials()
                .withAk(accessKeyId)
                .withSk(accessKeySecret);
        return DnsClient.newBuilder()
                .withCredential(auth)
                .withRegion(DnsRegion.valueOf("cn-east-3"))
                .build();
    }


    /**
     * 创建域名解析
     *
     * @param client     DnsClient
     * @param domainName domainName
     * @param recordType recordType
     * @param value      value
     * @return
     */
    public static CreateRecordSetResponse addDomainRecord(DnsClient client, String domainName, String recordType, String value) {
        LOG.info("添加域名解析记录的结果(json)↓ domainName={},  recordType={},value={}"
                , domainName
                , recordType
                , value);
        CreateRecordSetRequest request = new CreateRecordSetRequest();
        try {
            // 所属zone ID。
            // 公网Zone ID可以通过查询公网Zone列表获取。
            // 内网Zone ID可以通过查询内网Zone列表获取。
            String zoneId = zones(client).getZones().get(0).getId();
            request.withZoneId(zoneId);
            CreateRecordSetRequestBody body = new CreateRecordSetRequestBody();
            body.withName(domainName); // 域名，后缀需以zone name结束且为FQDN（即以“.”号结束的完整主机名）。
            body.withType(recordType);
            body.withTtl(300);
            List<String> records = new ArrayList<>();
            records.add("\"" + value + "\""); // 解析记录的值。不同类型解析记录对应的值的规则不同。
            body.withRecords(records);
            request.withBody(body);
            // todo  出现错误：type 'TXT' in line 'default_view'，进行修改或者删除
            CreateRecordSetResponse response = client.createRecordSet(request);
            if (LOG.isDebugEnabled()) {
                LOG.debug(JSON.toJSONString(response));
            }
            // 轮询检查状态
            String recordSetId = response.getId();
            String status = response.getStatus();
            // 设置轮询超时时间和计数器
            final int MAX_RETRIES = 24; // 最多轮询12次
            final int POLLING_INTERVAL = 5000; // 5秒
            int retryCount = 0;

            while ("PENDING_CREATE".equals(status) && retryCount < MAX_RETRIES) {
                Thread.sleep(POLLING_INTERVAL);
                retryCount++;

                ShowRecordSetRequest showRequest = new ShowRecordSetRequest()
                        .withZoneId(zoneId)
                        .withRecordsetId(recordSetId);
                ShowRecordSetResponse showResponse = client.showRecordSet(showRequest);
                status = showResponse.getStatus();
                LOG.info("Current status: {} (attempt {}/{})", status, retryCount, MAX_RETRIES);
            }

            if (retryCount >= MAX_RETRIES && "PENDING_CREATE".equals(status)) {
                LOG.warn("Record set creation is taking longer than expected. Last status: {}", status);
            }

            LOG.info("Record Set creation process completed. Final status: {}, Set ID: {}", status, recordSetId);
            return response;
        } catch (Exception e) {
            if (e instanceof ServiceResponseException es) {
                LOG.error("轮询检查状态失败,Error Code:{},Message:{}", es.getErrorCode(), es.getErrorMsg(), e);
            }
            throw new BusinessException("添加域名解析记录的结果",e);
        }
    }

    /**
     * 删除域名解析
     *
     * @param client   DnsClient
     * @param recordId recordId
     * @param zoneId   zoneId
     * @return
     */
    public static DeleteRecordSetResponse deleteDomainRecord(DnsClient client, String recordId, String zoneId) {
        LOG.info("删除域名解析记录的结果(json)↓");
        try {
            DeleteRecordSetRequest request = new DeleteRecordSetRequest()
                    .withZoneId(zoneId)
                    .withRecordsetId(recordId);
            DeleteRecordSetResponse response = client.deleteRecordSet(request);
            if (LOG.isDebugEnabled()) {
                LOG.debug(JSON.toJSONString(response));
            }
            return response;
        } catch (Exception error) {
            LOG.error("删除域名解析记录的结果:", error);
            throw error;
        }
    }

    /**
     * 删除域名解析
     *
     * @param client DnsClient
     * @param record CreateRecordSetResponse
     * @return
     */
    public static DeleteRecordSetResponse deleteDomainRecord(DnsClient client, CreateRecordSetResponse record) {
        return deleteDomainRecord(client, record.getId(), record.getZoneId());
    }

    public static ListPublicZonesResponse zones(DnsClient client) {
        ListPublicZonesRequest request = new ListPublicZonesRequest();
        try {
            return client.listPublicZones(request);
        } catch (Exception error) {
            LOG.error("查询单个公网Zone:", error);
            throw error;
        }
    }

    public static ListRecordSetsByZoneResponse listRecordSetsByZone(DnsClient client, DnsDomain domain) {
        return listRecordSetsByZone(client, domain, 500);
    }

    public static ListRecordSetsByZoneResponse listRecordSetsByZone(DnsClient client, DnsDomain domain, Integer pageSize) {
        ListRecordSetsByZoneRequest request = new ListRecordSetsByZoneRequest()
                .withZoneId(domain.getDomainId())
                .withLimit(pageSize);
        try {
            return client.listRecordSetsByZone(request);
        } catch (Exception error) {
            LOG.error("查询租户Record Set资源列表:", error);
            throw error;
        }
    }

    public static ShowRecordSetByZoneResponse showRecordSetByZone(DnsClient client, DnsDomain domain) {
        return showRecordSetByZone(client, domain, 500);
    }

    public static ShowRecordSetByZoneResponse showRecordSetByZone(DnsClient client, DnsDomain domain, Integer pageSize) {
        ShowRecordSetByZoneRequest request = new ShowRecordSetByZoneRequest()
                .withZoneId(domain.getDomainId())
                .withLimit(pageSize);
        try {
            return client.showRecordSetByZone(request);
        } catch (Exception error) {
            LOG.error("查询单个Zone下Record Set列表:", error);
            throw error;
        }
    }
}
